
#include "MarchingCubes.h"

#include "BBox.h"
#include "SpatialData.h"

MarchingCubes::MarchingCubes(SpatialData *data)
:	data(data)
{
}

void MarchingCubes::setSpatialData(SpatialData *data)
{
	this->data = data;
}

SpatialData* MarchingCubes::getSpatialData()
{
	return data;
}


Mesh* MarchingCubes::generateMesh(int xRes, int yRes, int zRes, float threshold){
    Mesh *mesh = new Mesh;

	for(int i = 0; i < xRes; i++)
		for(int j = 0; j < yRes; j++)
			for(int k = 0; k < zRes; k++){
				Cube cube = getCube(xRes, yRes, zRes, i, j, k);
				cube.handleCase(threshold, mesh);
			}

	return mesh;
}


MarchingCubes::Cube MarchingCubes::getCube(int xRes, int yRes, int zRes, int i, int j, int k)
{
	BBox bbox = data->getBoundingBox();
	float xInc = bbox.getXDim()/(xRes - 1.0);
	float yInc = bbox.getYDim()/(yRes - 1.0);
	float zInc = bbox.getZDim()/(zRes - 1.0);

	// i j k
	Vec3 pos = Vec3(bbox.pMin.x + i*xInc, bbox.pMin.y + j*yInc, bbox.pMin.z + k*zInc);
	Node node1(pos, data->getValue(pos.x, pos.y, pos.z));
	// i j k+1
	pos = Vec3(bbox.pMin.x + i*xInc, bbox.pMin.y + j*yInc, bbox.pMin.z + (k+1)*zInc);
	Node node2(pos, data->getValue(pos.x, pos.y, pos.z));
	// i j+1 k+1
	pos = Vec3(bbox.pMin.x + i*xInc, bbox.pMin.y + (j+1)*yInc, bbox.pMin.z + (k+1)*zInc);
	Node node3(pos, data->getValue(pos.x, pos.y, pos.z));
	// i j+1 k
	pos = Vec3(bbox.pMin.x + i*xInc, bbox.pMin.y + (j+1)*yInc, bbox.pMin.z + k*zInc);
	Node node4(pos, data->getValue(pos.x, pos.y, pos.z));
	// i+1 j k
	pos = Vec3(bbox.pMin.x + (i+1)*xInc, bbox.pMin.y + j*yInc, bbox.pMin.z + k*zInc);
	Node node5(pos, data->getValue(pos.x, pos.y, pos.z));
	// i+1 j k+1
	pos = Vec3(bbox.pMin.x + (i+1)*xInc, bbox.pMin.y + j*yInc, bbox.pMin.z + (k+1)*zInc);
	Node node6(pos, data->getValue(pos.x, pos.y, pos.z));
	// i+1 j+1 k+1
	pos = Vec3(bbox.pMin.x + (i+1)*xInc, bbox.pMin.y + (j+1)*yInc, bbox.pMin.z + (k+1)*zInc);
	Node node7(pos, data->getValue(pos.x, pos.y, pos.z));
	// i+1 j+1 k
	pos = Vec3(bbox.pMin.x + (i+1)*xInc, bbox.pMin.y + (j+1)*yInc, bbox.pMin.z + k*zInc);
	Node node8(pos, data->getValue(pos.x, pos.y, pos.z));

	return Cube(node1, node2, node3, node4, node5, node6, node7, node8);
}


int MarchingCubes::Cube::findCase(float threshold) {
    int caseindex = 0;
    
    if(vertices[0].value < threshold)
        caseindex |= 1;
    if(vertices[1].value < threshold)
        caseindex |= 2; 
    if(vertices[2].value < threshold)
        caseindex |= 4;
    if(vertices[3].value < threshold)
        caseindex |= 8; 
    if(vertices[4].value < threshold)
        caseindex |= 16;
    if(vertices[5].value < threshold)
        caseindex |= 32; 
    if(vertices[6].value < threshold)
        caseindex |= 64;
    if(vertices[7].value < threshold)
        caseindex |= 128;

    return caseindex;
}


void MarchingCubes::Cube::handleCase(float threshold, Mesh *m) {
    int caseindex = findCase(threshold);
    switch(caseindex) {
        //Todos os pontos têm valor maior que o threshold - 1
        case 0:
        //Todos os pontos têm valor menor que o threshold - 1
        case 255:
            break;
        //Apenas um vértice está abaixo ou acima do threshold - 16
        case 1: //v0 abaixo
        case 254: //v0 acima
        case 2: //v1 abaixo
        case 253: //v1 acima
        case 4: //v2 abaixo
        case 251: //v2 acima
        case 8: //v3 abaixo
        case 247: //v3 acima
        case 16: //v4 abaixp
        case 239: //v4 acima
        case 32: //v5 abaixo
        case 223: //v5 acima
        case 64: //v6 abaixo
        case 191: //v6 acima
        case 128: //v7 abaixo
        case 127: //v7 acima
            handleSubCase0(threshold, caseindex, m);
            break;
        //2 vértices adjacentes estão acima ou abaixo do threshold - 24
        case 3: //v0 e v1 menor que threshold
        case 252: //complemento
        case 48: //v4 e v5 menor que threshold
        case 207: //complemento
        case 192: //v6 e v7 menores que threshold
        case 63: //complemento
        case 12: //v2 e v3 menores que o threshold
        case 243: //complemento
        case 17: //v0 e v4 menores que o threshold
        case 238: //complemento
        case 34: //v1 e v5
        case 221:
        case 136: //v3 e v7
        case 119:
        case 68: //v2 e v6
        case 187:
        case 9: //v0 e v3
        case 246: 
        case 6: //v1 e v2
        case 249:
        case 96: //v5 e v6
        case 159:
        case 144: //v4 e v7
        case 111:
            handleSubCase1(threshold, caseindex, m);
            break;
        //2 vértices não adjacentes maiores ou menores que o threshold 32
        case 5: //v0 e v2 mesma face
        case 250:
        case 10: //v1 v3 mesma face
        case 245:
        case 66: //v1 v6 mesma face
        case 189:
        case 36: //v2 e v5 mesma face
        case 219:
        case 160: //v5 e v7 mesma face
        case 95:
        case 90: //v4 e v6 mesma face
        case 165:
        case 24: //v4 e v3 mesma face
        case 231:
        case 129: // v0 e v7 mesma face
        case 126:
        case 33: //v0 e v5 mesma face
        case 222:
        case 18: // v1 e v4 mesma face
        case 237:
        case 72: //v3 e v6 mesma face
        case 183:
        case 132: // v2 e v7 mesma face
        case 123:  
        case 65: //v0 e v6 diagonal
        case 190:
        case 130: //v1 e v7 diagonal
        case 125:
        case 40: //v3 e v5 diagonal
        case 215: 
        case 20://v2 e v4 diagonal
        case 235:
            handleSubCase2(threshold, caseindex, m); 
            break;
        //3 vértices adjacentes maiores ou menores que o threshold - 48
        case 19: //v1, v0, v4
        case 236:
        case 49://v0, v4, v5
        case 206:
        case 50: //v4, v5, v1
        case 205:
        case 35: //5, 1 ,0
        case 220:
        case 140: //2, 3, 7
        case 115:
        case 200: //3, 7, 6
        case 55:
        case 196: //7, 6, 2
        case 59:
        case 76: //6, 2, 3
        case 179:
        case 11: //1, 0, 3
        case 244:
        case 13: //0, 3, 2
        case 242:
        case 14: //3, 2, 1
        case 241:
        case 7: //2, 1, 0
        case 248:
        case 208: //6, 7, 4
        case 47:
        case 176: // 7 4 5
        case 79:
        case 112: //4, 5, 6
        case 143:
        case 224: //5, 6, 7
        case 31:
        case 70: //1 2 6
        case 185:
        case 100: //2 6 5
        case 155:
        case 98: //6 5 1 
        case 157:
        case 38: //5, 1, 2
        case 217:
        case 25: //3 0 4
        case 230:
        case 145: //0, 4, 7
        case 110:
        case 152: //4 7 3
        case 103:
        case 137: //7, 3, 0
        case 118:
            handleSubCase3(threshold, caseindex, m); 
            break;
        //4 vértices de uma face menores que o threshold - 6
        case 51: //0, 4, 5, 1
        case 204: //3, 2, 6, 7
        case 15: //2, 3, 0, 1
        case 240: // 6, 5, 4, 7
        case 153: // 7, 4, 0, 3
        case 102: // 2, 1, 5, 6
            handleSubCase4(threshold, caseindex, m);
            break;
        /*//3 vértices, compartilhando uma aresta - 48 casos
        //TODO caso é ambíguo e não foi testado
        case 21: //0, 4, 2 
        case 234:
        case 81: //0, 4, 6
        case 174:
        case 138: //3, 7, 1
        case 117:
        case 168: //3, 7, 5
        case 87:
        case 69: //2, 6 0
        case 186:
        case 84: //2, 6, 4
        case 171:
        case 42: //1, 5, 3
        case 213:
        case 162: //1, 5, 7
        case 93:
        case 67: //1, 0, 6
        case 188:
        case 131: //1, 0, 7
        case 124:
        case 44: //2, 3, 5
        case 211:
        case 28: //2, 3, 4
        case 227:
        case 194: //6, 7, 1
        case 61:
        case 193: // 6 , 7, 0
        case 62: 
        case 134: //1, 2, 7
        case 121:
        case 22: // 1, 2, 4
        case 233:
        case 41: //0, 3, 5
        case 214:
        case 73: //0, 3, 6
        case 182:
        case 97: //5, 6, 0
        case 158:
        case 104: //5, 6, 3
        case 151:
        case 146: //7, 4, 1
        case 109:
        case 148: //7, 4, 2
        case 107:
        case 52: //5, 4, 2
        case 203:
        case 56: //5, 4, 3
        case 199:
            handleSubCase5(threshold, caseindex, m);
            break;
        //4 vértices com 3 arestas compartilhadas
        //Variante 1 - vértice fora da face entre os outros 2
        //Os casos únicos serão 3 vértices TOP ou BOT
        //3 vértices bot
        case 27: //0, 1, 3, 4
        case 177: //0, 4, 5, 7
        case 114: //4, 5, 6, 1
        case 39: //0, 1, 2, 5
        //3 vértices top
        case 141: //0, 3, 2, 7
        case 216: //3, 7, 4, 6
        case 228: //7, 6, 5, 3
        case 78: //6, 2, 3, 1
            handleSubCase6(threshold, caseindex, m);
            break;
        //Variante 2 - 1 vértice fora da face pelo primeiro
        //3 vértices bot
        //FIXME não deu pra testar com a esfera, não entrou em nenhum desses casos.
        case 57: //3, 0, 4, 5
        case 178: //7, 4, 5, 1
        case 99: //6, 5, 1, 0
        case 23: //2, 1, 0, 4
        //3 vértices top
        case 77: //0, 3, 2, 6
        case 156: //4, 7, 3, 2
        case 198: //1, 2, 6, 7
        case 232: //5, 6, 7, 3
            handleSubCase7(threshold, caseindex, m);
            break;
        //Variante 3 - 1 vértice fora da face pelo último
        //3 vértices bot
        case 147: //1, 0, 4, 7
        case 113: //0, 4, 5, 6
        case 54: //4, 5, 1, 2
        case 43: //5, 1, 0, 3
        //3 vértices top
        case 108: //5, 6, 2, 3
        case 142: //7, 3, 2, 1
        case 201: //6, 7, 3, 0
        case 212: //2, 6, 7, 4
            handleSubCase8(threshold, caseindex, m);
            break;*/
    }
}


void MarchingCubes::Cube::handleSubCase0(float threshold, int caseindex, Mesh *m) {
    switch(caseindex) {
        case 1: //v0 menor
            subCase0(0, 1, 3, 4, threshold, m);
            break;
        case 254: //v0 maior
            subCase0(0, 1, 4, 3, threshold, m);
            break;
        case 2: //v1 menor
            subCase0(1, 0, 5, 2, threshold, m);
            break;
        case 253://v1 maior
            subCase0(1, 0, 2, 5, threshold, m);
            break;
        case 4: //v2 abaixo
            subCase0(2, 1, 6, 3, threshold, m);
            break;
        case 251: //v2 acima
            subCase0(2, 1, 3, 6, threshold, m);
            break;
        case 8: //v3 abaixo
            subCase0(3, 2 , 7, 0, threshold, m);
            break;
        case 247: //v3 acima
            subCase0(3, 2 , 0, 7, threshold, m);
            break;
        case 16: //v4 abaixo
            subCase0(4, 0, 7, 5, threshold, m);
            break;
        case 239: //v4 acima
            subCase0(4, 0 , 5, 7, threshold, m);
            break;
        case 32: //v5 abaixo
            subCase0(5, 6, 1, 4, threshold, m);
            break;
        case 223: //v5 acima
            subCase0(5, 6, 4, 1, threshold, m);
            break;
        case 64: //v6 abaixo
            subCase0(6, 2, 5, 7, threshold, m);
            break;
        case 191: //v6 acima
            subCase0(6, 2, 7, 5, threshold, m);
            break;
        case 128: //v7 abaixo
            subCase0(7, 3, 6, 4, threshold, m);
            break;
        case 127: //v7 acima
            subCase0(7, 3, 4, 6, threshold, m);
            break;
    }
}

void MarchingCubes::Cube::subCase0(int i, int j, int k, int l, float threshold, Mesh *m) {
    Vec3 ij = interpolate(i, j, threshold);
    Vec3 ik = interpolate(i, k, threshold);
    Vec3 il = interpolate(i, l, threshold);
    Vec3 normal = normalize(cross(ik - ij , il - ij));
    m->addFace(ij, ik, il, normal);
}


void MarchingCubes::Cube::handleSubCase1(float threshold, int caseindex, Mesh *m) {
    switch(caseindex) {
        case 3: //v0 e v1 menor que threshold
            subCase1(0, 3, 4, 1, 2, 5, threshold, m);
            break;
        case 252: //complemento
            subCase1(0, 4, 3, 1, 5, 2, threshold, m);
            break;
        case 48: //v4 e v5 menor que threshold
            subCase1(4, 0, 7, 5, 1, 6, threshold, m);
            break;
        case 207: //complemento
            subCase1(4, 7, 0, 5, 6, 1, threshold, m);
            break;
        case 192: //v6 e v7 menores que threshold
            subCase1(6, 2, 5, 7, 3, 4, threshold, m);
            break;
        case 63: //complemento
            subCase1(6, 5, 2, 7, 4, 3, threshold, m);
            break;
        case 12: //v2 e v3 menores que o threshold
            subCase1(3, 7, 0, 2, 6, 1, threshold, m);
            break;
        case 243: //complemento
            subCase1(3, 0, 7, 2, 1, 6, threshold, m);
            break;
        case 17: //v0 e v4 menores que o threshold
            subCase1(0, 1, 3, 4, 5, 7, threshold, m);
            break;
        case 238: //complemento
            subCase1(0, 3, 1, 4, 7, 5, threshold, m);
            break;
        case 34: //v1 e v5
            subCase1(1, 2, 0, 5, 6, 4, threshold, m);
            break;
        case 221:
            subCase1(1, 0, 2, 5, 4, 6, threshold, m);
            break;
        case 136: //v3 e v7
            subCase1(3, 0, 2, 7, 4, 6, threshold, m);
            break;
        case 119:
            subCase1(3, 2, 0, 7, 6, 4, threshold, m);
            break;
        case 68: //v2 e v6
            subCase1(2, 3, 1, 6, 7, 5, threshold, m);
            break;
        case 187:
            subCase1(2, 1, 3, 6, 5, 7, threshold, m);
            break;
        case 9: //v0 e v3
            subCase1(0, 4, 1, 3, 7, 2, threshold, m);
            break;
        case 246:
            subCase1(0, 1, 4, 3, 2, 7, threshold, m);
            break;
        case 6: //v1 e v2
            subCase1(1, 0, 5, 2, 3, 6, threshold, m);
            break;
        case 249:
            subCase1(1, 5, 0, 2, 6, 3, threshold, m);
            break;
        case 96: //v5 e v6
            subCase1(5, 1, 4, 6, 2, 7, threshold, m);
            break;
        case 159:
            subCase1(5, 4, 1, 6, 7, 2, threshold, m);
            break;
        case 144: //v4 e v7
            subCase1(4, 5, 0, 7, 6, 3, threshold, m);
            break;
        case 111:
            subCase1(4, 0, 5, 7, 3, 6, threshold, m);
            break;
    }
}


void MarchingCubes::Cube::subCase1(int i, int j, int k, int l, int m, int n, float threshold, Mesh *mesh) {
    Vec3 ij = interpolate(i, j, threshold);
    Vec3 ik = interpolate(i, k, threshold);
    Vec3 lm = interpolate(l, m, threshold);
    Vec3 ln = interpolate(l, n, threshold);

    //TODO criar 2 faces triangulares: (ij, ik, lm) e (lm, ik, ln)
    Vec3 normalf1 = normalize(cross(ik - ij, lm - ij));
    Vec3 normalf2 = normalize(cross(ik - lm, ln - lm));

    mesh->addFace(ij, ik, lm, normalf1);
    mesh->addFace(lm, ik, ln, normalf2);
}

//TODO: Encontrar algum caso para testar.
void MarchingCubes::Cube::handleSubCase2(float threshold, int caseindex, Mesh *m) {
    switch(caseindex) {
        case 5: //v0 e v2
            subCase2(0, 1, 3, 4, 2, 1, 3, 5, threshold, m);
            break;
        case 250:
            subCase2(0, 1, 4, 3, 2, 1, 5, 3, threshold, m);
            break;
        case 10: //v1 v3
            subCase2(1, 2, 0, 5, 3, 2, 7, 0, threshold, m);
            break;
        case 245:
            subCase2(1, 2, 5, 0, 3, 2, 0, 7, threshold, m);
            break;
        case 66: //v1 v6
            subCase2(1, 2, 0, 5, 6, 7, 2, 5, threshold, m);
            break;
        case 189:
            subCase2(1, 2, 5, 0, 6, 7, 5, 2, threshold, m);
            break;
        case 36: //v2 e v5
            subCase2(2, 1, 5, 3, 5, 6, 1, 4, threshold, m);
            break;
        case 219:
            subCase2(2, 5, 1, 3, 5, 6, 4, 1, threshold, m);
            break;
        case 160: //v5 e v7
            subCase2(5, 6, 1, 4, 7, 3, 6, 4, threshold, m);
            break;
        case 95:
            subCase2(5, 6, 4, 1, 7, 3, 4, 6, threshold, m);
            break;
        case 90: //v4 e v6
            subCase2(4, 7, 5, 0, 6, 7, 2, 5, threshold, m);
            break;
        case 165:
            subCase2(4, 7, 0, 5, 6, 7, 5, 2, threshold, m);
            break;
        case 24: //v4 e v3
            subCase2(4, 7, 5, 0, 3, 2, 7, 0, threshold, m);
            break;
        case 231:
            subCase2(4, 7, 0, 5, 3, 2, 0, 7, threshold, m);
            break;
        case 129: // v0 e v7
            subCase2(0, 1, 3, 4, 7, 3, 6, 4, threshold, m);
            break;
        case 126:
            subCase2(0, 1, 4, 3, 7, 3, 4, 6, threshold, m);
            break;
        case 33: //v0 e v5
            subCase2(0, 1, 3, 4, 5, 6, 1, 4, threshold, m);
            break;
        case 222:
            subCase2(0, 1, 4, 3, 5, 6, 4, 1, threshold, m);
            break;
        case 18: // v1 e v4
            subCase2(1, 2, 0, 5, 4, 7, 5, 0, threshold, m);
            break;
        case 237:
            subCase2(1, 2, 5, 0, 4, 7, 0, 5, threshold, m);
            break;
        case 72: //v3 e v6
            subCase2(3, 2, 7, 0, 6, 7, 2, 5, threshold, m);
            break;
        case 183:
            subCase2(3, 2, 0, 7, 6, 7, 5, 2, threshold, m);
            break;
        case 132: // v2 e v7
            subCase2(2, 1, 5, 3, 7, 3, 6, 4, threshold, m);
            break;
        case 123:  
            subCase2(2, 1, 3, 5, 7, 3, 4, 6, threshold, m);
            break;
        case 65: //v0 e v6
            subCase2(0, 1, 3, 4, 6, 7, 2, 5, threshold, m);
            break;
        case 190:
            subCase2(0, 1, 4, 3, 6, 7, 5, 2, threshold, m);
            break;
        case 130: //v1 e v7
            subCase2(1, 2, 0, 5, 7, 3, 6, 4, threshold, m);
            break;
        case 125:
            subCase2(1, 2, 5, 0, 7, 3, 4, 6, threshold, m);
            break;
        case 40: //v3 e v5
            subCase2(3, 2, 7, 0, 5, 6, 1, 4, threshold, m);
            break;
        case 215: 
            subCase2(3, 2, 0, 7, 5, 6, 4, 1, threshold, m);
            break;
        case 20://v2 e v4
            subCase2(2, 1, 6, 3, 4, 7, 5, 0, threshold, m);
            break;
        case 235:
            subCase2(2, 1, 3, 6, 4, 7, 0, 5, threshold, m);
            break;
    }
}

void MarchingCubes::Cube::subCase2(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh) {
    subCase0(i, j, k, l, threshold, mesh);
    subCase0(m, n, o, p, threshold, mesh);
}

void MarchingCubes::Cube::handleSubCase3(float threshold, int caseindex, Mesh *m) {
    switch(caseindex) {
        case 19: //v1, v0, v4
            subCase31(1, 2, 0, 3, 4, 7, 5, threshold, m);
            break;
        case 236:
            subCase32(1, 2, 0, 3, 4, 7, 5, threshold, m);
            break;
        case 49://v0, v4, v5
            subCase31(0, 3, 4, 7, 5, 6, 1, threshold, m);
            break;
        case 206:
            subCase32(0, 3, 4, 7, 5, 6, 1, threshold, m);
            break;
        case 50: //v4, v5, v1
            subCase31(4, 7, 5, 6, 1, 3, 0, threshold, m);
            break;
        case 205:
            subCase32(4, 7, 5, 6, 1, 3, 0, threshold, m);
            break;
        case 35: //5, 1, 0
            subCase31(5, 6, 1, 2, 0, 3, 4, threshold, m);
            break;
        case 220:
            subCase32(5, 6, 1, 2, 0, 3, 4, threshold, m);
            break;
        //FIXME: caso 2, 3, 7 deveria ser o subcase31, mas a normal
        //ficou errada, então os subcases foram trocados
        case 140: //2, 3, 7
            subCase32(2, 1, 3, 0, 7, 4, 6, threshold, m);
            break;
        case 115:
            subCase31(2, 1, 3, 0, 7, 4, 6, threshold, m);
            break;
        case 200: //3, 7, 6
            subCase32(3, 0, 7, 4, 6, 5, 2, threshold, m);
            break;
        case 55:
            subCase31(3, 0, 7, 4, 6, 5, 2, threshold, m);
            break;
        case 196: //7, 6, 2
            subCase32(7, 4, 6, 5, 2, 1, 3, threshold, m);
            break;
        case 59:
            subCase31(7, 4, 6, 5, 2, 1, 3, threshold, m);
            break;
        case 11: //1, 0, 3
            subCase32(1, 5, 0, 4, 3, 7, 2, threshold, m);
            break;
        case 244:
            subCase31(1, 5, 0, 4, 3, 7, 2, threshold, m);
            break;
        case 13: //0, 3, 2
            subCase32(0, 4, 3, 7, 2, 6, 1, threshold, m);
            break;
        case 242:
            subCase31(0, 4, 3, 7, 2, 6, 1, threshold, m);
            break;
        case 14: //3, 2, 1
            subCase32(3, 7, 2, 6, 1, 4, 0, threshold, m);
            break;
        case 241:
            subCase31(3, 7, 2, 6, 1, 4, 0, threshold, m);
            break;
        case 7: //2, 1, 0
            subCase32(2, 6, 1, 5, 0, 4, 3, threshold, m);
            break;
        case 248:
            subCase31(2, 6, 1, 5, 0, 4, 3, threshold, m);
            break;
        case 208: //6, 7, 4
            subCase32(6, 2, 7, 3, 4, 0, 5, threshold, m);
            break;
        case 47:
            subCase31(6, 2, 7, 3, 4, 0, 5, threshold, m);
            break;
        case 176: // 7 4 5
            subCase32(7, 3, 4, 0, 5, 1, 6, threshold, m);
            break;
        case 79:
            subCase31(7, 3, 4, 0, 5, 1, 6, threshold, m);
            break;
        case 112: //4, 5, 6
            subCase32(4, 0, 5, 1, 6, 2, 7, threshold, m);
            break;
        case 143:
            subCase31(4, 0, 5, 1, 6, 2, 7, threshold, m);
            break;
        case 224: //5, 6, 7
            subCase32(5, 1, 6, 2, 7, 3, 4, threshold, m);
            break;
        case 31:
            subCase31(5, 1, 6, 2, 7, 3, 4, threshold, m);
            break;
        case 70: //1 2 6
            subCase32(1, 0, 2, 3, 6, 7, 5, threshold, m);
            break;
        case 185:
            subCase31(1, 0, 2, 3, 6, 7, 5, threshold, m);
            break;
        case 100: //2 6 5
            subCase32(2, 3, 6, 7, 5, 4, 1, threshold, m);
            break;
        case 155:
            subCase31(2, 3, 6, 7, 5, 4, 1, threshold, m);
            break;
        case 98://6 5 1 
            subCase32(6, 7, 5, 4, 1, 0, 2, threshold, m);
            break;
        case 157:
            subCase31(6, 7, 5, 4, 1, 0, 2, threshold, m);
            break;
        case 38: //5, 1, 2
            subCase32(5, 4, 1, 0, 2, 3, 6, threshold, m);
            break;
        case 117:
            subCase31(5, 4, 1, 0, 2, 3, 6, threshold, m);
            break;
        case 25://3 0 4
            subCase32(3, 2, 0, 1, 4, 5, 7, threshold, m);
            break;
        case 230:
            subCase31(3, 2, 0, 1, 4, 5, 7, threshold, m);
            break;
        case 145: //0, 4, 7
            subCase32(0, 1, 4, 5, 7, 6, 3, threshold, m);
            break;
        case 110:
            subCase31(0, 1, 4, 5, 7, 6, 3, threshold, m);
            break;
        case 152: //4 7 3
            subCase32(4, 5, 7, 6, 3, 2, 0, threshold, m);
            break;
        case 103:
            subCase31(4, 5, 7, 6, 3, 2, 0, threshold, m);
            break;
        case 137: //7, 3, 0
            subCase32(7, 6, 3, 2, 0, 1, 4, threshold, m);
            break;
        case 118:
            subCase31(7, 6, 3, 2, 0, 1, 4, threshold, m);
            break;
    }
}

void MarchingCubes::Cube::subCase31(int i, int j, int k, int l, int m, int n, int o, float threshold, Mesh *mesh) {
    Vec3 ij = interpolate(i, j, threshold);
    Vec3 kl = interpolate(k, l, threshold);
    Vec3 mn = interpolate(m, n, threshold);
    Vec3 io = interpolate(i, o, threshold);
    Vec3 mo = interpolate(m, o, threshold); 
    //TODO criar face (ij, kl, mn)
    Vec3 normalf1 = normalize(cross(kl - ij, mn - ij));
    mesh->addFace(ij, kl, mn, normalf1);
    
    //TODO criar face (ij, mn, io)
    Vec3 normalf2 = normalize(cross(mn - ij, io - ij));
    mesh->addFace(ij, mn, io, normalf2);
    
    //TODO criar face(io, mn, mo)
    Vec3 normalf3 = normalize(cross(mn - io, mo - io));
    mesh->addFace(io, mn, mo, normalf3);
}

void MarchingCubes::Cube::subCase32(int i, int j, int k, int l, int m, int n, int o, float threshold, Mesh *mesh) {
    Vec3 ij = interpolate(i, j, threshold);
    Vec3 kl = interpolate(k, l, threshold);
    Vec3 mn = interpolate(m, n, threshold);
    Vec3 io = interpolate(i, o, threshold);
    Vec3 mo = interpolate(m, o, threshold); 
    //TODO criar face (ij, mn, kl)
    Vec3 normalf1 = normalize(cross(mn - ij, kl - ij));
    mesh->addFace(ij, mn, kl, normalf1);
    
    //TODO criar face (ij, io, mn)
    Vec3 normalf2 = normalize(cross(io - ij, mn - ij));
    mesh->addFace(ij, io, mn, normalf2);
    
    //TODO criar face(io, mn, mo)
    Vec3 normalf3 = normalize(cross(mo - io, mn - io));
    mesh->addFace(io, mo, mn, normalf3);
}


void MarchingCubes::Cube::handleSubCase4(float threshold, int caseindex, Mesh *m) {
    switch(caseindex) {
        case 51: //0, 4, 5, 1
            subCase4(0, 4, 5, 1, 3, 7, 6, 2, threshold, m);
            break;
        case 204: //3, 2, 6, 7
            subCase4(3, 2, 6, 7, 0, 1, 5, 4, threshold, m);
            break;
        case 15: //2, 3, 0, 1
            subCase4(2, 3, 0, 1, 6, 7, 4, 5, threshold, m);
            break;
        case 240: // 6, 5, 4, 7
            subCase4(6, 5, 4, 7, 2, 1, 0, 3, threshold, m);
            break;
        case 153: // 7, 4, 0, 3
            subCase4(7, 4, 0, 3, 6, 5, 1, 2, threshold, m);
            break;
        case 102: // 2, 1, 5, 6
            subCase4(2, 1, 5, 6, 3, 0, 4, 7, threshold, m);
            break;
    }
}


void MarchingCubes::Cube::subCase4(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh) {
    Vec3 im = interpolate(i, m, threshold);
    Vec3 jn = interpolate(j, n, threshold);
    Vec3 ko = interpolate(k, o, threshold);
    //TODO criar face(im, ko, jn)
    Vec3 normalf1 = normalize(cross(jn - im, ko - im)); 
    mesh->addFace(im, jn, ko, normalf1);

    //TODO criar face(im, ko, lp)
    Vec3 lp = interpolate(l, p, threshold);
    Vec3 normalf2 = normalize(cross(ko - im, lp - im));
    mesh->addFace(im, ko, lp, normalf2);
}


void MarchingCubes::Cube::handleSubCase5(float threshold, int caseindex, Mesh *m) {
    switch(caseindex) {
        case 21: //0, 4, 2 
            subCase5(0, 1, 3, 4, 5, 7, 2, 1, 6, 3, threshold, m);
            break;
        case 243:
            subCase5(0, 3, 1, 4, 5, 7, 2, 1, 3, 6, threshold, m);
            break;
        case 81: //0, 4, 6
            subCase5(0, 1, 3, 4, 5, 7, 6, 2, 5, 7, threshold, m);
            break;
        case 174:
            subCase5(0, 3, 1, 4, 5, 7, 6, 2, 7, 5, threshold, m);
            break;
        case 138: //3, 7, 1
            subCase5(3, 0, 2, 7, 4, 6, 0, 1, 3, 4, threshold, m);
            break;
        case 117:
            subCase5(3, 2, 0, 7, 6, 4, 0, 1, 4, 5, threshold, m);
            break;
        case 168: //3, 7, 5
            subCase5(3, 0, 2, 7, 4, 6, 5, 6, 1, 4, threshold, m);
            break;
        case 87:
            subCase5(3, 2, 0, 7, 6, 4, 5, 6, 4, 1, threshold, m);
            break;
        case 69: //2, 6 0
            subCase5(2, 3, 1, 6, 7, 5, 0, 1, 3, 4, threshold, m);
            break;
        case 186:
            subCase5(2, 1, 3, 6, 5, 7, 0, 1, 4, 3, threshold, m);
            break;
        case 84: //2, 6, 4
            subCase5(2, 3, 1, 6, 7, 5, 4, 0, 7, 5, threshold, m);
            break;
        case 171:
            subCase5(2, 1, 3, 6, 5, 7, 4, 0, 5, 7, threshold, m);
            break;
        case 42: //1, 5, 3
            subCase5(1, 2, 0, 5, 6, 4, 3, 2, 7, 0, threshold, m);
            break;
        case 213:
            subCase5(1, 0, 2, 5, 4, 6, 3, 2, 0, 7,  threshold, m);
            break;
        case 162: //1, 5, 7
            subCase5(1, 2, 0, 5, 6, 4, 7, 3, 6, 4, threshold, m);
            break;
        case 93:
            subCase5(1, 0, 2, 5, 4, 6, 7, 3, 4, 6,  threshold, m);
            break;
        case 67: //1, 0, 6
            subCase5(0, 3, 4, 1, 2, 5, 6, 2, 5, 7, threshold, m);
            break;
        case 188:
            subCase5(0, 4, 3, 1, 5, 2, 6, 2, 7, 5, threshold, m);
            break;
        case 131: //1, 0, 7
            subCase5(0, 3, 4, 1, 2, 5, 7, 3, 4, 6, threshold, m);
            break;
        case 124:
            subCase5(0, 4, 3, 1, 5, 2, 7, 4, 6, 4, threshold, m);
            break;
        case 44: //2, 3, 5
            subCase5(2, 1, 5, 3, 0, 7, 5, 6, 1, 4, threshold, m);
            break;
        case 211:
            subCase5(2, 5, 1, 3, 7, 0, 5, 6, 4, 1, threshold, m);
            break;
        case 28: //2, 3, 4
            subCase5(2, 1, 5, 3, 0, 7, 4, 0, 7, 5, threshold, m);
            break;
        case 227:
            subCase5(2, 5, 1, 3, 7, 0, 4, 0, 7, 5, threshold, m);
            break;
        case 194: //6, 7, 1
            subCase5(6, 2, 5, 7, 3, 4, 1, 0 ,5, 2,  threshold, m);
            break;
        case 61:
            subCase5(6, 5, 2, 7, 4, 3, 1, 0, 2, 5, threshold, m);
            break;
        case 193: //6, 7, 0
            subCase5(6, 2, 5, 7, 3, 4, 0, 1, 5, 2,  threshold, m);
            break;
        case 62: 
            subCase5(6, 5, 2, 7, 4, 3, 0, 1, 2, 5, threshold, m);
            break;
        case 134: //1, 2, 7
            subCase5(1, 0, 5, 2, 3, 6, 7, 3, 4, 6, threshold, m);
            break;
        case 121:
            subCase5(1, 5, 0, 2, 6, 3, 7, 3, 6, 4, threshold, m);
            break;
        case 22: // 1, 2, 4
            subCase5(1, 0, 5, 2, 3, 6, 4, 0, 7, 6, threshold, m);
            break;
        case 233:
            subCase5(1, 5, 0, 2, 6, 3, 7, 3, 6, 7, threshold, m);
            break;
        case 41: //0, 3, 5
            subCase5(0, 4, 1, 3, 7, 2, 5, 6, 1, 4, threshold, m);
            break;
        case 214:
            subCase5(0, 1, 4, 3, 2, 7, 5, 6, 4, 1, threshold, m);
            break;
        case 73: //0, 3, 6
            subCase5(0, 4, 1, 3, 7, 2, 6, 2, 5, 7, threshold, m);
            break;
        case 182:
            subCase5(0, 1, 4, 3, 2, 7, 6, 3, 7, 5, threshold, m);
            break;
        case 97: //5, 6, 0
            subCase5(5, 1, 4, 6, 2, 7, 0, 1, 3, 4, threshold, m);
            break;
        case 158:
            subCase5(5, 4, 1, 6, 7, 2, 0, 1, 4, 3, threshold, m);
            break;
        case 104: //5, 6, 3
            subCase5(5, 1, 4, 6, 2, 7, 3, 2, 7, 0, threshold, m);
            break;
        case 151:
            subCase5(5, 4, 1, 6, 7, 2, 3, 2, 0, 7, threshold, m);
            break;
        case 146: //7, 4, 1
            subCase5(4, 5, 0, 7, 6, 3, 1, 0, 5, 2, threshold, m);
            break;
        case 109:
            subCase5(4, 0, 5, 7, 3, 6, 1, 0, 2, 5, threshold, m);
            break;
        case 148: //7, 4, 2
            subCase5(4, 5, 0, 7, 6, 3, 2, 1, 6, 3, threshold, m);
            break;
        case 107:
            subCase5(4, 0, 5, 7, 3, 6, 2, 1, 3, 6, threshold, m);
            break;
        case 52: //5, 4, 2
            subCase5(4, 0, 7, 5, 1, 6, 2, 1, 6, 3, threshold, m);
            break;
        case 203:
            subCase5(4, 7, 0, 5, 6, 1, 2, 1, 3, 6, threshold, m);
            break;
        case 56: //5, 4, 3
            subCase5(4, 0, 7, 5, 1, 6, 3, 2, 7, 0, threshold, m);
            break;
        case 199:
            subCase5(4, 7, 0, 5, 6, 1, 3, 2, 7, 0, threshold, m);
            break;
    }
}

void MarchingCubes::Cube::subCase5(int i, int j, int k, int l, int m, int n, int o, int p, int q, int r, float threshold, Mesh *mesh) {
    subCase1(i, j, k, l, m, n, threshold, mesh);
    subCase0(o, p, q, r, threshold, mesh);
}

void MarchingCubes::Cube::handleSubCase6(float threshold, int caseindex, Mesh *m) {
    switch(caseindex) {
        case 27: //0, 1, 3, 4
            subCase61(3, 0, 1, 4, 2, 7, 5, threshold, m);
            break;
        case 177: //0, 4, 5, 7
            subCase61(7, 4, 0, 5, 3, 6, 1, threshold, m);
            break;
        case 114: //4, 5, 6, 1
            subCase61(6, 5, 4, 1, 7, 2, 0, threshold, m);
            break;
        case 39: //0, 1, 2, 5
            subCase61(2, 1, 5, 0, 6, 3, 4, threshold, m);
            break;
        case 141: //0, 3, 2, 7
            subCase62(0, 3, 2, 7, 1, 4, 5, threshold, m);
            break;
        case 216: //3, 7, 4, 6
            subCase62(4, 7, 3, 6, 0, 5, 2, threshold, m);
            break;
        case 228: //7, 6, 5, 2
            subCase62(5, 6, 7, 2, 4, 1, 3, threshold, m);
            break;
        case 78: //6, 2, 3, 1
            subCase62(1, 2, 6, 3, 5, 0, 7, threshold, m);
            break;
    }
}


void MarchingCubes::Cube::subCase61(int i, int j, int k, int l, int m, int n, int o, float threshold, Mesh *mesh) {
    Vec3 im = interpolate(i, m, threshold);
    Vec3 km = interpolate(k, m, threshold);
    Vec3 in = interpolate(i, n, threshold);
    Vec3 ko = interpolate(k, o, threshold);
    Vec3 ln = interpolate(l, n, threshold);
    Vec3 lo = interpolate(l, o, threshold);

    //TODO criar face(im, kn, in)
    Vec3 normalf1 = normalize(cross(in - im, km - im)); 
    mesh->addFace(im, in, km, normalf1);

    //TODO criar face(in, kn, ko)
    Vec3 normalf2 = normalize(cross(ko - in, km - in)); 
    mesh->addFace(in, ko, km, normalf2);
    
    //TODO criar face(in, ko, ln)
    Vec3 normalf3 = normalize(cross(in - ko, ln - ko)); 
    mesh->addFace(ko, in, ln, normalf3);

    //TODO criar face(ln, ko, lo)
    Vec3 normalf4 = normalize(cross(lo - ln, ko - ln)); 
    mesh->addFace(ln, lo, ko, normalf4);
}

void MarchingCubes::Cube::subCase62(int i, int j, int k, int l, int m, int n, int o, float threshold, Mesh *mesh) {
    Vec3 im = interpolate(i, m, threshold);
    Vec3 km = interpolate(k, m, threshold);
    Vec3 in = interpolate(i, n, threshold);
    Vec3 ko = interpolate(k, o, threshold);
    Vec3 ln = interpolate(l, n, threshold);
    Vec3 lo = interpolate(l, o, threshold);

    //TODO criar face(im, kn, in)
    Vec3 normalf1 = normalize(cross(km - im, in - im)); 
    mesh->addFace(im, km, in, normalf1);

    //TODO criar face(in, kn, ko)
    Vec3 normalf2 = normalize(cross(km - in, ko - in)); 
    mesh->addFace(in, km, ko, normalf2);
    
    //TODO criar face(in, ko, ln)
    Vec3 normalf3 = normalize(cross(ln - ko, in - ko)); 
    mesh->addFace(ko, ln, in, normalf3);

    //TODO criar face(ln, ko, lo)
    Vec3 normalf4 = normalize(cross(ko - ln, lo - ln)); 
    mesh->addFace(ln, ko, lo, normalf4);
}

void MarchingCubes::Cube::handleSubCase7(float threshold, int caseindex, Mesh *m) {
    switch(caseindex) {
        case 57: //3, 0, 4, 5
            subCase71(3, 0, 4, 5, 2, 7, 1, 6, threshold, m);
            break;
        case 178: //7, 4, 5, 1
            subCase71(7, 4, 5, 1, 3, 6, 0, 2, threshold, m);
            break;
        case 99: //6, 5, 1, 0
            subCase71(6, 5, 1, 0, 7, 2, 4, 3, threshold, m);
            break;
        case 23: //2, 1, 0, 4
            subCase71(2, 1, 0, 4, 6, 3, 5, 7, threshold, m);
            break;
        case 77: //0, 3, 2, 6
            subCase72(0, 3, 2, 6, 4, 1, 5, 7, threshold, m);
            break;
        case 156: //4, 7, 3, 2
            subCase72(4, 7, 3, 2, 5, 0, 6, 1, threshold, m);
            break;
        case 198: //1, 2, 6, 7
            subCase72(1, 2, 6, 7, 0, 5, 3, 4, threshold, m);
            break;
        case 232: //5, 6, 7, 3
            subCase72(5, 6, 7, 3, 1, 4, 2, 0, threshold, m);
            break;
    }
}

void MarchingCubes::Cube::subCase71(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh) {
    Vec3 im = interpolate(i, m, threshold);
    Vec3 kn = interpolate(k, n, threshold);
    Vec3 in = interpolate(i, n, threshold);
    Vec3 om = interpolate(o, m, threshold);
    Vec3 lp = interpolate(l, p, threshold);
    Vec3 lo = interpolate(l, o, threshold);

    //TODO criar face(im, kn, in)
    Vec3 normalf1 = normalize(cross(in - im, kn - im)); 
    mesh->addFace(im, in, kn, normalf1);

    //TODO criar face(in, kn, ko)
    Vec3 normalf2 = normalize(cross(kn - im, lo - im)); 
    mesh->addFace(im, kn, lo, normalf2);
    
    //TODO criar face(in, ko, ln)
    Vec3 normalf3 = normalize(cross(lo - im, om - im)); 
    mesh->addFace(im, lo, om, normalf3);

    //TODO criar face(ln, ko, lo)
    Vec3 normalf4 = normalize(cross(lp - kn, lo - kn)); 
    mesh->addFace(kn, lp, lo, normalf4);
}

void MarchingCubes::Cube::subCase72(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh) {
    Vec3 im = interpolate(i, m, threshold);
    Vec3 kn = interpolate(k, n, threshold);
    Vec3 in = interpolate(i, n, threshold);
    Vec3 om = interpolate(o, m, threshold);
    Vec3 lp = interpolate(l, p, threshold);
    Vec3 lo = interpolate(l, o, threshold);

    //TODO criar face(im, kn, in)
    Vec3 normalf1 = normalize(cross(kn - im, in - im)); 
    mesh->addFace(im, kn, in, normalf1);

    //TODO criar face(in, kn, ko)
    Vec3 normalf2 = normalize(cross(lo - im, kn - im)); 
    mesh->addFace(im, lo, kn, normalf2);
    
    //TODO criar face(in, ko, ln)
    Vec3 normalf3 = normalize(cross(om - im, lo - im)); 
    mesh->addFace(im, om, lo, normalf3);

    //TODO criar face(ln, ko, lo)
    Vec3 normalf4 = normalize(cross(lo - kn, lp - kn)); 
    mesh->addFace(kn, lo, lp, normalf4);
}

void MarchingCubes::Cube::handleSubCase8(float threshold, int caseindex, Mesh *m) {
    switch(caseindex) {
        case 147: //1, 0, 4, 7
            subCase81(1, 0, 4, 7, 3, 6, 2, 5, threshold, m);
            break;
        case 113: //0, 4, 5, 6
            subCase81(0, 4, 5, 6, 7, 2, 3, 1, threshold, m);
            break;
        case 54: //4, 5, 1, 2
            subCase81(4, 5, 1, 2, 7, 2, 3, 0, threshold, m);
            break;
        case 43: //5, 1, 0, 3
            subCase81(5, 1, 0, 3, 2, 7, 6, 4, threshold, m);
            break;
        case 108: //5, 6, 2, 3
            subCase82(5, 6, 2, 3, 1, 4, 0, 7, threshold, m);
            break;
        case 142: //7, 3, 2, 1
            subCase82(1, 2, 3, 7, 5, 0, 4, 6, threshold, m);
            break;
        case 201: //6, 7, 3, 0
            subCase82(0, 3, 7, 6, 4, 1, 5, 2, threshold, m);
            break;
        case 212: //2, 6, 7, 4
            subCase82(4, 7, 6, 2, 5, 0, 1, 3, threshold, m);
            break;
    }
}

void MarchingCubes::Cube::subCase81(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh) {
    Vec3 lm = interpolate(l, m, threshold);
    Vec3 ln = interpolate(l, n, threshold);
    Vec3 jm = interpolate(j, m, threshold);
    Vec3 ip = interpolate(i, p, threshold);
    Vec3 kp = interpolate(k, p, threshold);
    Vec3 io = interpolate(i, o, threshold);
    Vec3 mo = interpolate(m, o, threshold);

    //TODO criar face(im, kn, in)
    Vec3 normalf1 = normalize(cross(ln - lm, jm - lm)); 
    mesh->addFace(lm, ln, jm, normalf1);

    //TODO criar face(in, kn, ko)
    Vec3 normalf2 = normalize(cross(ip - ln, jm - ln)); 
    mesh->addFace(ln, ip, jm, normalf2);
    
    //TODO criar face(in, ko, ln)
    Vec3 normalf3 = normalize(cross(kp - ln, ip - ln)); 
    mesh->addFace(ln, kp, ip, normalf3);

    //TODO criar face(ln, ko, lo)
    Vec3 normalf4 = normalize(cross(mo - io, ip - io)); 
    mesh->addFace(io, mo, ip, normalf4);
}

void MarchingCubes::Cube::subCase82(int i, int j, int k, int l, int m, int n, int o, int p, float threshold, Mesh *mesh) {
    Vec3 lm = interpolate(l, m, threshold);
    Vec3 ln = interpolate(l, n, threshold);
    Vec3 jm = interpolate(j, m, threshold);
    Vec3 ip = interpolate(i, p, threshold);
    Vec3 kp = interpolate(k, p, threshold);
    Vec3 io = interpolate(i, o, threshold);
    Vec3 mo = interpolate(m, o, threshold);

    //TODO criar face(im, kn, in)
    Vec3 normalf1 = normalize(cross(jm - lm, ln - lm)); 
    mesh->addFace(lm, jm, ln, normalf1);

    //TODO criar face(in, kn, ko)
    Vec3 normalf2 = normalize(cross(jm - ln, ip - ln)); 
    mesh->addFace(ln, jm, ip, normalf2);
    
    //TODO criar face(in, ko, ln)
    Vec3 normalf3 = normalize(cross(ip - ln, kp - ln)); 
    mesh->addFace(ln, ip, kp, normalf3);

    //TODO criar face(ln, ko, lo)
    Vec3 normalf4 = normalize(cross(ip - io, mo - io)); 
    mesh->addFace(io, ip, mo, normalf4);
}

Vec3 MarchingCubes::Cube::interpolate(int i, int j, float threshold) {
    float t = (threshold - vertices[i].value);
    float u = t/(vertices[j].value - vertices[i].value);
    Vec3 v = vertices[i].position + (vertices[j].position - vertices[i].position)*u;
    return v;
}
